//
// Created by Luis on 2022/4/14.
//

#include "LYFFmpeg.h"

LYFFmpeg::LYFFmpeg(LYPlaystatus *playstatus, LYCallJava *callJava, const char *url) {
    this->playstatus = playstatus;
    this->callJava = callJava;
    this->url = url;
    pthread_mutex_init(&seek_mutex, NULL);
}

LYFFmpeg::~LYFFmpeg() {
    pthread_mutex_destroy(&seek_mutex);
}

void *decodeFFmpeg(void *data) {
    LYFFmpeg *wlFFmpeg = (LYFFmpeg *) data;
    wlFFmpeg->decodeFFmpegThread();
    pthread_exit(&wlFFmpeg->decodeThread);
}

void LYFFmpeg::parpared() {
    pthread_create(&decodeThread, NULL, decodeFFmpeg, this);
}

void LYFFmpeg::decodeFFmpegThread() {
    LOGE("decodeFFmpegThread");
    av_register_all();
    avformat_network_init();
    pFormatCtx = avformat_alloc_context();
    if(avformat_open_input(&pFormatCtx, url, NULL, NULL) != 0) {
        if(LOG_DEBUG) {
            LOGE("can not open url :%s", url);
        }
        return;
    }
    if(avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        if(LOG_DEBUG) {
            LOGE("can not find streams from %s", url);
        }
        return;
    }

    for(int i = 0; i < pFormatCtx->nb_streams; i++) {
        if(pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            if(audio == NULL) {
                audio = new LYAudio(playstatus, pFormatCtx->streams[i]->codecpar->sample_rate, callJava);
                audio->streamIndex = i;
                audio->duration = pFormatCtx->duration / AV_TIME_BASE;
                audio->time_base = pFormatCtx->streams[i]->time_base;
                audio->codecpar = pFormatCtx->streams[i]->codecpar;
                duration = audio->duration;
            }
        }
    }
    AVCodec *dec = avcodec_find_decoder(audio->codecpar->codec_id);
    if(!dec) {
        if(LOG_DEBUG) {
            LOGE("can not find decoder");
        }
        return;
    }
    audio->avCodecContext = avcodec_alloc_context3(dec);
    if(!audio->avCodecContext) {
        if(LOG_DEBUG) {
            LOGE("can not alloc new decodecctx");
        }
        return;
    }

    if(avcodec_parameters_to_context(audio->avCodecContext, audio->codecpar) < 0) {
        if(LOG_DEBUG) {
            LOGE("can not fill decodecctx");
        }
        return;
    }

    if(avcodec_open2(audio->avCodecContext, dec, 0) != 0) {
        if(LOG_DEBUG) {
            LOGE("cant not open audio strames");
        }
        return;
    }
    LOGE("decodeFFmpegThread end");
    callJava->onCallParpared(CHILD_THREAD);
}


void LYFFmpeg::start() {
    if(audio == NULL) {
        if(LOG_DEBUG) {
            LOGE("audio is null");
            return;
        }
    }
    audio->play();
    int count = 0;
    while(playstatus != NULL && !playstatus->exit) {
        if(playstatus->seek) {
            continue;
        }
        if(audio->queue->getQueueSize() > 40){
            continue;
        }
        AVPacket *avPacket = av_packet_alloc();
        if(av_read_frame(pFormatCtx, avPacket) == 0)
        {
            if(avPacket->stream_index == audio->streamIndex) {
                audio->queue->putAvpacket(avPacket);
            } else{
                av_packet_free(&avPacket);
                av_free(avPacket);
            }
        } else{
            av_packet_free(&avPacket);
            av_free(avPacket);
            while(playstatus != NULL && !playstatus->exit) {
                if(audio->queue->getQueueSize() > 0) {
                    continue;
                } else{
                    playstatus->exit = true;
                    break;
                }
            }
        }
    }

    if(LOG_DEBUG)  {
        LOGD("解码完成");
    }
}

void LYFFmpeg::pause() {
    if(audio != NULL) {
        audio->pause();
    }
}

void LYFFmpeg::resume() {
    if(audio != NULL)  {
        audio->resume();
    }
}

void LYFFmpeg::setMute(jint mute) {
    if(audio != NULL)  {
        audio->setMute(mute);
    }
}

void LYFFmpeg::setVolume(int percent) {
    if(audio != NULL) {
        audio->setVolume(percent);
    }
}

void LYFFmpeg::seek(jint secds) {
    if (duration <= 0) {
        return;
    }
    if (secds >= 0 && secds <= duration) {
        if (audio != NULL) {
            playstatus->seek = true;
            audio->queue->clearAvpacket();
            audio->clock = 0;
            audio->last_time = 0;
            pthread_mutex_lock(&seek_mutex);
            int64_t rel = secds * AV_TIME_BASE;
            avformat_seek_file(pFormatCtx, -1, INT64_MIN, rel, INT64_MAX, 0);
            pthread_mutex_unlock(&seek_mutex);
            playstatus->seek = false;
        }
    }
}

